home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-12-21 | 13.1 KB | 346 lines | [TEXT/GADA] |
- -- Simple Elevator Simulatiion Program
- --
- -- By Arthur V. Lopes - (C) 1993
-
- -- Package (generic): Elevator_Simulation
-
-
- GENERIC
-
- No_Elevators : Natural;
- Elevator_Capacity : Natural;
- No_Floors : Natural;
- No_Passengers : Natural;
-
- PACKAGE Elevator_Simulation IS
-
- SUBTYPE Floor_Type IS Integer RANGE 1..No_Floors;
- SUBTYPE Elevator_Type IS Integer RANGE 1..No_Elevators;
- SUBTYPE Passenger_Type IS Integer RANGE 1..No_Passengers;
- SUBTYPE Capacity_Type IS Integer RANGE 0..Elevator_Capacity;
- -- SUBTYPE Screen_Depth IS Integer RANGE 1..24; -- See package screen
- -- SUBTYPE Screen_Width IS Integer RANGE 1..80;
-
- TYPE State IS (Going_Up, Going_Down, Neutral, In_Maintenance);
-
- TYPE Passenger_Waiting IS RECORD
- Id : Passenger_Type;
- Where : Floor_Type;
- Go_To : Floor_Type;
- Time_In : Natural;
- Direction : State;
- END RECORD;
-
- TASK Generate_Passengers IS
- ENTRY Start;
- END Generate_Passengers;
-
- TASK TYPE Elevator_Task_Type IS
- ENTRY Turn_Key_On(Elevator_Id : Elevator_Type);
- END Elevator_Task_Type;
-
- TASK Control IS
- ENTRY Start;
- ENTRY Open_Doors_Building;
- ENTRY Get_New_Passenger(Passenger : Passenger_Waiting);
- ENTRY At_Floor(Floor_No : Floor_Type;
- Unit : Elevator_Type;
- Going : State);
- ENTRY Shut_Down;
- END Control;
-
- Elevator : ARRAY(Elevator_Type) OF Elevator_Task_Type;
-
- Total_Wait_Time : Natural := 0;
-
- END Elevator_Simulation;
-
-
- WITH Screen_IO; USE Screen_IO;
- WITH Random; USE Random;
- WITH Text_IO; USE Text_IO;
- WITH My_Int_IO; USE My_Int_IO;
- WITH Calendar; USE Calendar;
- PACKAGE BODY Elevator_Simulation IS
-
- Passenger_Load : CONSTANT := 32;
-
- Passengers_To_Go : Natural := No_Passengers;
-
- Load : ARRAY(Elevator'RANGE) OF Capacity_Type := (OTHERS => 0);
-
- Stops : ARRAY(Elevator'RANGE,1..No_Floors) OF Natural;
-
- Activity : ARRAY(Elevator'RANGE) OF State := (OTHERS => Neutral);
-
- Waiting : ARRAY(1..No_Passengers) OF Passenger_Waiting;
- No_Waiting: Natural := 0;
-
- In_Unit : ARRAY(Elevator'RANGE,1..Elevator_Capacity) OF Passenger_Waiting;
- No_In_Unit : ARRAY(Elevator'RANGE) OF Natural := (OTHERS => 0);
-
-
- FUNCTION Tell_Me_Where_I_Am RETURN Floor_Type IS
- BEGIN
- RETURN Random_Int(Floor_Type'LAST);
- END;
-
- FUNCTION Floor_To_Go(From_Floor : Floor_Type) RETURN Floor_Type IS
- Temp : Floor_Type;
- BEGIN
- Temp := Random_Int(Floor_Type'LAST);
- WHILE Temp = From_Floor LOOP
- Temp := Random_Int(Floor_Type'LAST);
- END LOOP;
- RETURN Temp;
- END;
-
- TASK BODY Generate_Passengers IS
- I : Natural := 0;
- One : Passenger_Waiting;
- BEGIN
- ACCEPT Start;
- While I < No_Passengers LOOP
- IF (Random_Int(181) MOD 2) = 0 THEN
- I := I + 1;
- One.Id := I;
- One.Where := Tell_Me_Where_I_Am;
- One.Go_To := Floor_To_Go(One.Where);
- IF One.Where > One.Go_To THEN
- One.Direction := Going_Down;
- ELSE
- One.Direction := Going_Up;
- END IF;
- One.Time_In := Natural( Seconds (Clock));
- Control.Get_New_Passenger(One);
- END IF;
- END LOOP;
- END Generate_Passengers;
-
- TASK BODY Elevator_Task_Type IS
-
- Old_Activity : State := Neutral;
- My_Id : Elevator_Type;
- Current_Floor : Natural := 1;
- Old_Where : Floor_Type := Floor_Type'FIRST;
- Stoped : Boolean;
-
- PROCEDURE Move IS
- BEGIN
- CASE Activity(My_Id) IS
- WHEN Going_Up =>
- Current_Floor := Current_Floor + 1;
- IF Current_Floor > No_Floors THEN
- Current_Floor := No_Floors;
- Activity(My_Id) := Going_Down;
- ELSE
- DELAY 0.1; -- Time to reach this floor
- END IF;
- WHEN Going_Down =>
- Current_Floor := Current_Floor - 1;
- IF Current_Floor < 1 THEN
- Current_Floor := 1;
- Activity(My_Id) := Going_Up;
- ELSE
- DELAY 0.1; -- Time to reach this floor
- END IF;
- WHEN Neutral =>
- Activity(My_Id) := Going_Up;
- WHEN In_Maintenance =>
- Delay 100.0;
- WHEN OTHERS =>
- NULL;
- END CASE;
- FOR J IN 1..No_Floors LOOP
- Terminal.WriteAt(Where => (My_ID + 5, J * 2 + 14), What => " ");
- END LOOP;
- Terminal.WriteAt(Where => (My_Id + 5, Current_Floor * 2 + 14),
- What => Integer'IMAGE(Load(My_Id)));
- END Move;
-
- BEGIN
- ACCEPT Turn_Key_On(Elevator_Id : Elevator_Type) DO
- My_Id := Elevator_Id;
- END Turn_Key_On;
- Terminal.WriteAt(Where => (My_Id + 5, 1),
- What => "Elevator " & Integer'IMAGE(My_Id));
- --Screen_Mgm.Msg(My_Id + 5, 1,"Elevator " & Integer'IMAGE(My_Id));
- LOOP
- IF Passengers_To_Go <= 0 THEN
- EXIT;
- END IF;
- Terminal.WriteAt(Where => (My_Id + 5, Old_where * 2 + 14),
- What => " ");
- Terminal.WriteAt(Where => (My_Id + 5, Current_Floor * 2 + 14),
- What => Integer'IMAGE(Load(My_Id)));
-
- Stoped := False;
-
- IF No_In_Unit(My_Id) > 0 AND Passengers_To_Go > 0 THEN
- FOR I IN 1..No_In_Unit(My_Id) LOOP
- IF In_Unit(My_Id,I).Go_To = Current_FLoor THEN
- -- Allow passengers to get in / out; Control unit
- Control.At_Floor(Current_Floor,My_Id,Activity(My_Id));
- Stoped := True;
- EXIT;
- END IF;
- END LOOP;
- END IF;
-
- IF NOT Stoped THEN
- IF Stops(My_Id,Current_Floor) > 0 AND
- No_In_Unit(My_Id) < Elevator_Capacity THEN
- Control.At_Floor(Current_Floor,My_Id,Activity(My_Id));
- END IF;
- END IF;
-
- Move;
-
- IF Activity(My_Id) /= Old_Activity THEN
- Old_Activity := Activity(My_Id);
- DELAY 0.2; -- Accelaration / Dessacelaration factor
- END IF;
- Old_Where := Current_Floor;
-
- END LOOP;
-
- END Elevator_Task_Type;
-
-
- TASK BODY Control IS
- From_Elevator : Elevator_Type;
- From_Floor : Floor_Type;
- Unit : Elevator_Type;
- Last_Unit : Elevator_Type := Elevator'FIRST;
- I : Natural;
-
- FUNCTION Best_Unit(Current_Floor : Floor_Type) RETURN Elevator_Type IS
- BU : Elevator_Type := 1;
- DBU : Natural := 0;
- D : Natural;
- BEGIN
- -- For now just do a circular assignment
- IF Last_Unit = Elevator'LAST THEN
- Last_Unit := Elevator'FIRST;
- ELSE
- Last_Unit := Last_Unit + 1;
- END IF;
- RETURN Last_Unit;
- END Best_Unit;
-
- BEGIN
- ACCEPT Start;
- FOR I IN Elevator'RANGE LOOP
- FOR J IN 1..No_Floors LOOP
- Stops(I,J) := 0; -- Clear stops
- END LOOP;
- Elevator(I).Turn_Key_On(I);
- END LOOP;
- ACCEPT Open_Doors_Building;
- Generate_Passengers.Start;
- LOOP
- IF Passengers_To_Go <= 0 THEN
- EXIT;
- END IF;
- SELECT
- WHEN No_Waiting < Passenger_Load =>
- ACCEPT Get_New_Passenger(Passenger : Passenger_Waiting) DO
- No_Waiting := No_Waiting + 1;
- Waiting(No_Waiting) := Passenger;
- Unit := Best_Unit(Waiting(No_Waiting).Where);
- Stops(Unit,Waiting(No_Waiting).Where) :=
- Stops(Unit,Waiting(No_Waiting).Where) + 1;
- Terminal.WriteAt(Where => (2, Passenger.Id * 2 + 14),
- What => Integer'IMAGE(Passenger.Where));
- Terminal.WriteAt(Where => (3, Passenger.Id * 2 + 14),
- What => Integer'IMAGE(Passenger.Go_To));
- Terminal.WriteAt(Where => (4, Passenger.Id * 2 + 14),
- What => " ");
- END Get_New_Passenger;
- OR
- ACCEPT At_Floor(Floor_No : Floor_Type;
- Unit : Elevator_Type;
- Going : State) DO
- -- Allow passengers to get out
- I := 1;
- WHILE I <= No_In_Unit(Unit) LOOP
- IF In_Unit(Unit,I).Go_To = Floor_No THEN
- Total_Wait_Time := Total_Wait_Time +
- Natural ( Seconds (Clock)) -
- In_Unit(Unit,I).Time_In;
- Terminal.WriteAt(Where => (4, In_Unit(Unit,I).Id * 2 + 14),
- What => " *");
- -- Put passenger outside elevator
- FOR J IN I..No_In_Unit(Unit) - 1 LOOP
- In_Unit(Unit,J) := In_Unit(Unit,J + 1);
- END LOOP;
- No_In_Unit(Unit) := No_In_Unit(Unit) - 1;
- IF Load(Unit) > 0 THEN
- Load(Unit) := Load(Unit) - 1;
- END IF;
- FOR J IN 1..No_Floors LOOP
- Terminal.WriteAt(Where => (Unit + 5, J * 2 + 14),
- What => " ");
- END LOOP;
- Terminal.WriteAt(Where => (Unit + 5, Floor_No * 2 + 14),
- What => Integer'IMAGE(No_In_Unit(Unit)));
- Passengers_To_Go := Passengers_To_Go - 1;
- ELSE
- I := I + 1;
- END IF;
- END LOOP;
- -- Now allow passengers to get in
- I := 1;
- WHILE I <= No_Waiting LOOP
- IF Waiting(I).Where = Floor_No THEN
- IF No_In_Unit(Unit) < Elevator_Capacity THEN
- -- AND Going = Waiting(I).Direction THEN
- -- Put passenger inside elevator
- No_In_Unit(Unit) := No_In_Unit(Unit) + 1;
- In_Unit(Unit,No_In_Unit(Unit)) := Waiting(I);
- IF Stops(Unit,Floor_No) > 0 THEN
- Stops(Unit,Floor_No) := Stops(Unit,Floor_No) - 1;
- END IF;
- Load(Unit) := Load(Unit) + 1;
- FOR J IN 1..No_Floors LOOP
- Terminal.WriteAt(Where => (Unit + 5, J * 2 + 14),
- What => " ");
- END LOOP;
- Terminal.WriteAt(Where => (Unit + 5, Floor_No * 2 + 14),
- What => Integer'IMAGE(Load(Unit)));
- FOR J IN I..No_Waiting - 1 LOOP
- Waiting(J) := Waiting(J + 1);
- END LOOP;
- No_Waiting := No_Waiting - 1;
- ELSE
- I := I + 1;
- END IF;
- ELSE
- I := I + 1;
- END IF;
- END LOOP;
- END At_Floor;
- OR
- TERMINATE;
- END SELECT;
- END LOOP;
- ACCEPT Shut_Down;
-
- EXCEPTION
- WHEN CONSTRAINT_ERROR =>
- Terminal.WriteAt(Where => (23,1), What => "Unit=" & Integer'IMAGE(Unit));
- Terminal.WriteAt(Where => (23,9),
- What => "N_In_U(U)=" & INTEGER'IMAGE(No_In_Unit(Unit)));
- Terminal.WriteAt(Where => (24,1),
- What => "P G in I=" & Integer'IMAGE(I));
- Terminal.WriteAt(Where => (24,15),
- What => " No_Waiting=" & Integer'IMAGE(No_Waiting));
- FOR J IN 1..No_Waiting LOOP
- Terminal.WriteAt(Where => (24,32+J),
- What => Integer'IMAGE(Waiting(j).Go_To) & " ");
- END LOOP;
- END Control;
-
- END Elevator_Simulation;
-
-